/* **********************************************************************************
*
* Copyright (c) Microsoft Corporation. All rights reserved.
*
* **********************************************************************************/

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;

namespace Theme_Builder
{
    public partial class EditImage : UserControl
    {
        private Color placeholderColor;
        private ColorMods color1Mods;
        private ColorMods color2Mods;

        public EditImage()
        {
            InitializeComponent();

            this.placeholderColor = Color.Fuchsia;
            this.color1Mods = new ColorMods();
            this.color2Mods = new ColorMods();

            this.comboBoxAlignment.SelectedIndex = 0;
            this.comboBoxFlip.SelectedIndex = 0;
        }

        public Color PlaceholderColor
        {
            set
            {
                this.placeholderColor = value;
                this.UpdateColors();
            }
        }

        public OfficeOpenXMLInterop.CT_BlipFillProperties ImageFill
        {
            get
            {
                return this.GetImageFill();
            }
            set
            {
                this.SetImageFill(value);
            }
        }

        private OfficeOpenXMLInterop.CT_BlipFillProperties GetImageFill()
        {
            OfficeOpenXMLInterop.CT_BlipFillProperties imageFill = new OfficeOpenXMLInterop.CT_BlipFillProperties();

            imageFill.rotWithShape = this.checkBoxRotateWithShape.Checked;

            // Add the location to the image here, this should not be output this way
            //  and will need to be parsed and handled by the output to .thmx process
            imageFill.blip = new OfficeOpenXMLInterop.CT_Blip();
            imageFill.blip.embed = this.pictureBoxImage.ImageLocation;
            
            if (this.checkBoxDuotone.Checked)
            {
                OfficeOpenXMLInterop.CT_DuotoneEffect duotone = new OfficeOpenXMLInterop.CT_DuotoneEffect();
                OfficeOpenXMLInterop.CT_SchemeColor color1 = new OfficeOpenXMLInterop.CT_SchemeColor();
                OfficeOpenXMLInterop.CT_SchemeColor color2 = new OfficeOpenXMLInterop.CT_SchemeColor();

                color1.val = OfficeOpenXMLInterop.ST_SchemeColorVal.phClr;
                Converters.ParseModifications(ref color1, this.color1Mods);

                color2.val = OfficeOpenXMLInterop.ST_SchemeColorVal.phClr;
                Converters.ParseModifications(ref color2, this.color2Mods);

                duotone.Items = new object[2];
                duotone.Items[0] = color1;
                duotone.Items[1] = color2;

                imageFill.blip.Items = new object[1];
                imageFill.blip.Items[0] = duotone;
            }

            // If we're not tiled, then stretch the image
            if (!this.checkBoxTile.Checked)
            {
                imageFill.stretch = new OfficeOpenXMLInterop.CT_StretchInfoProperties();
            }
            else
            {
                imageFill.tile = new OfficeOpenXMLInterop.CT_TileInfoProperties();

                imageFill.tile.algnSpecified = true;

                // TODO: figure out a better way to handle this and add it to the converters
                switch (this.comboBoxAlignment.Text)
                {
                    case "Top Left":
                        imageFill.tile.algn = OfficeOpenXMLInterop.ST_RectAlignment.tl;
                        break;
                    case "Top":
                        imageFill.tile.algn = OfficeOpenXMLInterop.ST_RectAlignment.t;
                        break;
                    case "Top Right":
                        imageFill.tile.algn = OfficeOpenXMLInterop.ST_RectAlignment.tr;
                        break;
                    case "Left":
                        imageFill.tile.algn = OfficeOpenXMLInterop.ST_RectAlignment.l;
                        break;
                    case "Center":
                        imageFill.tile.algn = OfficeOpenXMLInterop.ST_RectAlignment.ctr;
                        break;
                    case "Right":
                        imageFill.tile.algn = OfficeOpenXMLInterop.ST_RectAlignment.r;
                        break;
                    case "Bottom Left":
                        imageFill.tile.algn = OfficeOpenXMLInterop.ST_RectAlignment.bl;
                        break;
                    case "Bottom":
                        imageFill.tile.algn = OfficeOpenXMLInterop.ST_RectAlignment.b;
                        break;
                    case "Bottom Right":
                        imageFill.tile.algn = OfficeOpenXMLInterop.ST_RectAlignment.br;
                        break;
                }

                imageFill.tile.flipSpecified = true;

                switch (this.comboBoxFlip.Text)
                {
                    case "None":
                        imageFill.tile.flip = OfficeOpenXMLInterop.ST_TileFlipMode.none;
                        break;
                    case "X":
                        imageFill.tile.flip = OfficeOpenXMLInterop.ST_TileFlipMode.x;
                        break;
                    case "Y":
                        imageFill.tile.flip = OfficeOpenXMLInterop.ST_TileFlipMode.y;
                        break;
                    case "XY":
                        imageFill.tile.flip = OfficeOpenXMLInterop.ST_TileFlipMode.xy;
                        break;
                }

                imageFill.tile.sx = Int32.Parse(this.textBoxScaleX.Text) * 1000;
                imageFill.tile.sxSpecified = true;
                imageFill.tile.sy = Int32.Parse(this.textBoxScaleY.Text) * 1000;
                imageFill.tile.sySpecified = true;

                imageFill.tile.tx = Int32.Parse(this.textBoxOffsetX.Text) * 1000;
                imageFill.tile.txSpecified = true;
                imageFill.tile.ty = Int32.Parse(this.textBoxOffsetY.Text) * 1000;
                imageFill.tile.tySpecified = true;
            }
            
            return imageFill;
        }

        private void SetImageFill(OfficeOpenXMLInterop.CT_BlipFillProperties imageFill)
        {
            if (imageFill == null)
                return;

            this.checkBoxRotateWithShape.Checked = imageFill.rotWithShape;

            if (imageFill.tile != null)
            {
                this.checkBoxTile.Checked = true;

                if (imageFill.tile.txSpecified)
                    this.textBoxOffsetX.Text = (imageFill.tile.tx / 1000).ToString();
                if (imageFill.tile.tySpecified)
                    this.textBoxOffsetY.Text = (imageFill.tile.ty / 1000).ToString();
                if (imageFill.tile.sxSpecified)
                    this.textBoxScaleX.Text = (imageFill.tile.sx / 1000).ToString();
                if (imageFill.tile.sySpecified)
                    this.textBoxScaleY.Text = (imageFill.tile.sy / 1000).ToString();

                if (imageFill.tile.algnSpecified)
                {
                    switch (imageFill.tile.algn)
                    {
                        case OfficeOpenXMLInterop.ST_RectAlignment.b:
                            this.comboBoxAlignment.Text = "Bottom";
                            break;
                        case OfficeOpenXMLInterop.ST_RectAlignment.bl:
                            this.comboBoxAlignment.Text = "Bottom Left";
                            break;
                        case OfficeOpenXMLInterop.ST_RectAlignment.br:
                            this.comboBoxAlignment.Text = "Bottom Right";
                            break;
                        case OfficeOpenXMLInterop.ST_RectAlignment.ctr:
                            this.comboBoxAlignment.Text = "Center";
                            break;
                        case OfficeOpenXMLInterop.ST_RectAlignment.l:
                            this.comboBoxAlignment.Text = "Left";
                            break;
                        case OfficeOpenXMLInterop.ST_RectAlignment.r:
                            this.comboBoxAlignment.Text = "Right";
                            break;
                        case OfficeOpenXMLInterop.ST_RectAlignment.t:
                            this.comboBoxAlignment.Text = "Top";
                            break;
                        case OfficeOpenXMLInterop.ST_RectAlignment.tl:
                            this.comboBoxAlignment.Text = "Top Left";
                            break;
                        case OfficeOpenXMLInterop.ST_RectAlignment.tr:
                            this.comboBoxAlignment.Text = "Top Right";
                            break;
                    }
                }

                if (imageFill.tile.flipSpecified)
                {
                    switch (imageFill.tile.flip)
                    {
                        case OfficeOpenXMLInterop.ST_TileFlipMode.none:
                            this.comboBoxFlip.Text = "None";
                            break;
                        case OfficeOpenXMLInterop.ST_TileFlipMode.x:
                            this.comboBoxFlip.Text = "X";
                            break;
                        case OfficeOpenXMLInterop.ST_TileFlipMode.xy:
                            this.comboBoxFlip.Text = "XY";
                            break;
                        case OfficeOpenXMLInterop.ST_TileFlipMode.y:
                            this.comboBoxFlip.Text = "Y";
                            break;
                    }
                }
            }

            if (imageFill.blip != null)
            {
                if (imageFill.blip.embed != null)
                {
                    // We're expecting a path to an image here, this should be getting handled
                    //  by the load process in some way that we get an actual path to an image

                    try
                    {
                        Image img = Image.FromFile(imageFill.blip.embed);
                        this.pictureBoxImage.ImageLocation = imageFill.blip.embed;

                        if (img != null)
                        {
                            this.SetImageToPictureBox(img);
                        }
                    }
                    catch (Exception /*ex*/)
                    {
                        System.Diagnostics.Debug.Assert(false, "Unable to load the image");
                    }
                }

                if (imageFill.blip.Items != null)
                {
                    foreach (object obj in imageFill.blip.Items)
                    {
                        // handle a duotone effect if there is one applied to this image
                        if (obj.GetType() == typeof(OfficeOpenXMLInterop.CT_DuotoneEffect))
                        {
                            OfficeOpenXMLInterop.CT_DuotoneEffect duotone = (OfficeOpenXMLInterop.CT_DuotoneEffect)obj;

                            this.checkBoxDuotone.Checked = true;

                            if (duotone.Items.Length >= 2)
                            {
                                if (duotone.Items[0].GetType() == typeof(OfficeOpenXMLInterop.CT_SchemeColor))
                                {
                                    OfficeOpenXMLInterop.CT_SchemeColor color1 = (OfficeOpenXMLInterop.CT_SchemeColor)duotone.Items[0];

                                    this.color1Mods = Converters.GetColorModifications(color1);
                                }

                                if (duotone.Items[1].GetType() == typeof(OfficeOpenXMLInterop.CT_SchemeColor))
                                {
                                    OfficeOpenXMLInterop.CT_SchemeColor color2 = (OfficeOpenXMLInterop.CT_SchemeColor)duotone.Items[1];

                                    this.color2Mods = Converters.GetColorModifications(color2);
                                }

                                this.UpdateColors();
                            }
                        }
                    }
                }
            }
        }

        // Force an update of the colors being used
        private void UpdateColors()
        {
            this.panelColor1.Invalidate();
            this.panelColor2.Invalidate();
        }

        private void panelImage_Click(object sender, EventArgs e)
        {
            // TODO: add a "click here to insert image" as the default image within this panel so that
            //  people know they can click on this to insert the image

            if (this.openFileDialog1.ShowDialog(this) == DialogResult.OK)
            {
                Image img = null;

                try
                {
                    string filename = this.openFileDialog1.FileName;
                    img = Image.FromFile(filename);
                    this.pictureBoxImage.ImageLocation = filename;
                }
                catch (Exception /*ex*/)
                {
                    MessageBox.Show("Unable to open the specified Image, please try again.");
                    return;
                }

                this.SetImageToPictureBox(img);
            }
        }

        /// <summary>
        /// Fits the image correctly into the picture box.
        /// </summary>
        /// <param name="img">Image to fit</param>
        private void SetImageToPictureBox(Image img)
        {
            // This gets called on load??  Perhaps with the .Image property of this class?
            if (img == null)
                return;
            
            int maxH = this.panelImage.Height - 10;
            int maxW = this.panelImage.Width - 10;

            if (img.Height < maxH)
                maxH = img.Height;
            if (img.Width < maxW)
                maxW = img.Width;

            // If the image is landscape oriented
            if (img.Width > img.Height)
            {
                float ratio = (float)img.Height / (float)img.Width;

                this.pictureBoxImage.Width = maxW;
                this.pictureBoxImage.Height = (int)((float)maxW * ratio);

                if (this.pictureBoxImage.Height > maxH)
                {
                    this.pictureBoxImage.Height = maxH;
                    this.pictureBoxImage.Width = (int)((float)maxH / ratio);
                }
            }
            // If the image is portrait oriented
            else if (img.Width < img.Height)
            {
                float ratio = (float)img.Width / (float)img.Height;

                this.pictureBoxImage.Height = maxH;
                this.pictureBoxImage.Width = (int)((float)maxH * ratio);

                if (this.pictureBoxImage.Width > maxW)
                {
                    this.pictureBoxImage.Width = maxW;
                    this.pictureBoxImage.Height = (int)((float)maxW / ratio);
                }
            }
            // If the image is square
            else
            {
                this.pictureBoxImage.Height = maxH;
                this.pictureBoxImage.Width = maxH;
            }

            // Center the picture box
            int picWidth = this.pictureBoxImage.Width;
            int picHeight = this.pictureBoxImage.Height;
            int panelWidth = this.panelImage.Width;
            int panelHeight = this.panelImage.Height;

            int left = panelWidth / 2 - picWidth / 2;
            int top = panelHeight / 2 - picHeight / 2;

            this.pictureBoxImage.Left = left;
            this.pictureBoxImage.Top = top;
            
            this.pictureBoxImage.Image = img;
        }

        private void checkBoxDuotone_CheckedChanged(object sender, EventArgs e)
        {
            if (checkBoxDuotone.Checked)
            {
                this.groupBoxDuotone.Enabled = true;
            }
            else
            {
                this.groupBoxDuotone.Enabled = false;
            }
        }

        private void checkBoxTile_CheckedChanged(object sender, EventArgs e)
        {
            if (checkBoxTile.Checked)
            {
                this.groupBoxTile.Enabled = true;
            }
            else
            {
                this.groupBoxTile.Enabled = false;
            }
        }

        private void panelColor1_Click(object sender, EventArgs e)
        {
            ColorPickerExpanded cpe = new ColorPickerExpanded();
            cpe.ColorModifications = this.color1Mods;

            if (cpe.ShowDialog(this) == DialogResult.OK)
            {
                this.color1Mods = cpe.ColorModifications;

                this.UpdateColors();
            }
        }

        private void panelColor1_Paint(object sender, PaintEventArgs e)
        {
            if (!this.checkBoxDuotone.Checked)
                return;

            Graphics g = Graphics.FromHwnd(this.panelColor1.Handle);

            RectangleF bounds = g.VisibleClipBounds;

            Color color = Converters.ModifyColor(this.placeholderColor, this.color1Mods);

            SolidBrush sb = new SolidBrush(color);

            g.FillRectangle(sb, bounds);

            g.Dispose();
        }

        private void panelColor2_Click(object sender, EventArgs e)
        {
            ColorPickerExpanded cpe = new ColorPickerExpanded();
            cpe.ColorModifications = this.color2Mods;

            if (cpe.ShowDialog(this) == DialogResult.OK)
            {
                this.color2Mods = cpe.ColorModifications;

                this.UpdateColors();
            }
        }

        private void panelColor2_Paint(object sender, PaintEventArgs e)
        {
            if (!this.checkBoxDuotone.Checked)
                return;

            Graphics g = Graphics.FromHwnd(this.panelColor2.Handle);

            RectangleF bounds = g.VisibleClipBounds;

            Color color = Converters.ModifyColor(this.placeholderColor, this.color2Mods);

            SolidBrush sb = new SolidBrush(color);

            g.FillRectangle(sb, bounds);

            g.Dispose();
        }
    }
}
